d->arch.cpuids[i].input[1] = XEN_CPUID_INPUT_UNUSED;
}
+ /* For now, per-domain SoftTSC status is taken from global boot param. */
+ d->arch.vtsc = opt_softtsc;
+ spin_lock_init(&d->arch.vtsc_lock);
+
return 0;
fail:
set_int80_direct_trap(v);
switch_kernel_stack(v);
- cr4 = pv_guest_cr4_to_real_cr4(v->arch.guest_context.ctrlreg[4]);
+ cr4 = pv_guest_cr4_to_real_cr4(v);
if ( unlikely(cr4 != read_cr4()) )
write_cr4(cr4);
unsigned int opt_hvm_debug_level __read_mostly;
integer_param("hvm_debug", opt_hvm_debug_level);
-int opt_softtsc;
-boolean_param("softtsc", opt_softtsc);
-
struct hvm_function_table hvm_funcs __read_mostly;
/* I/O permission bitmap is globally shared by all HVM guests. */
#include <xen/smp.h>
#include <xen/irq.h>
#include <xen/softirq.h>
+#include <xen/keyhandler.h>
#include <asm/io.h>
#include <asm/msr.h>
#include <asm/mpspec.h>
static char opt_clocksource[10];
string_param("clocksource", opt_clocksource);
+int opt_softtsc;
+boolean_param("softtsc", opt_softtsc);
+
/*
* opt_consistent_tscs: All TSCs tick at the exact same rate, allowing
* simplified system time handling.
return gmtime(seconds);
}
+
+/*
+ * PV SoftTSC Emulation.
+ */
+
+static unsigned long rdtsc_kerncount, rdtsc_usercount;
+
+void pv_soft_rdtsc(struct vcpu *v, struct cpu_user_regs *regs)
+{
+ s_time_t now;
+
+ if ( guest_kernel_mode(v, regs) )
+ {
+ rdtsc_kerncount++;
+ rdtsc(regs->eax, regs->edx);
+ }
+ else
+ {
+ rdtsc_usercount++;
+ spin_lock(&v->domain->arch.vtsc_lock);
+ now = get_s_time() + v->domain->arch.vtsc_stime_offset;
+ if ( (int64_t)(now - v->domain->arch.vtsc_last) >= 0 )
+ v->domain->arch.vtsc_last = now;
+ else
+ now = v->domain->arch.vtsc_last;
+ spin_unlock(&v->domain->arch.vtsc_lock);
+ regs->eax = (uint32_t)now;
+ regs->edx = (uint32_t)(now >> 32);
+ }
+}
+
+static void dump_softtsc(unsigned char key)
+{
+ printk("softtsc count: %lu kernel, %lu user\n",
+ rdtsc_kerncount, rdtsc_usercount);
+}
+
+static struct keyhandler dump_softtsc_keyhandler = {
+ .diagnostic = 1,
+ .u.fn = dump_softtsc,
+ .desc = "dump softtsc stats"
+};
+
+static int __init setup_dump_softtsc(void)
+{
+ if ( opt_softtsc )
+ register_keyhandler('s', &dump_softtsc_keyhandler);
+ return 0;
+}
+__initcall(setup_dump_softtsc);
+
/*
* Local variables:
* mode: C
goto fail;
twobyte_opcode:
- /* Two-byte opcodes only emulated from guest kernel. */
- if ( !guest_kernel_mode(v, regs) )
+ /*
+ * All two-byte opcodes, except RDTSC (0x31) are executable only from
+ * guest kernel mode (virtual ring 0).
+ */
+ opcode = insn_fetch(u8, code_base, eip, code_limit);
+ if ( !guest_kernel_mode(v, regs) &&
+ !((opcode == 0x31) && v->domain->arch.vtsc) )
goto fail;
- /* Privileged (ring 0) instructions. */
- opcode = insn_fetch(u8, code_base, eip, code_limit);
if ( lock && (opcode & ~3) != 0x20 )
goto fail;
switch ( opcode )
case 4: /* Write CR4 */
v->arch.guest_context.ctrlreg[4] = pv_guest_cr4_fixup(*reg);
- write_cr4(pv_guest_cr4_to_real_cr4(
- v->arch.guest_context.ctrlreg[4]));
+ write_cr4(pv_guest_cr4_to_real_cr4(v));
break;
default:
}
case 0x31: /* RDTSC */
- rdtsc(regs->eax, regs->edx);
+ pv_soft_rdtsc(v, regs);
break;
case 0x32: /* RDMSR */
/* For Guest vMCA handling */
struct domain_mca_msrs vmca_msrs;
+
+ /* SoftTSC emulation */
+ bool_t vtsc;
+ s_time_t vtsc_last;
+ spinlock_t vtsc_lock;
+ int64_t vtsc_stime_offset;
} __cacheline_aligned;
#define has_arch_pdevs(d) (!list_empty(&(d)->arch.pdev_list))
unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4);
/* Convert between guest-visible and real CR4 values. */
-#define pv_guest_cr4_to_real_cr4(c) \
- (((c) | (mmu_cr4_features & (X86_CR4_PGE | X86_CR4_PSE))) & ~X86_CR4_DE)
+#define pv_guest_cr4_to_real_cr4(v) \
+ (((v)->arch.guest_context.ctrlreg[4] \
+ | (mmu_cr4_features & (X86_CR4_PGE | X86_CR4_PSE)) \
+ | ((v)->domain->arch.vtsc ? X86_CR4_TSD : 0)) \
+ & ~X86_CR4_DE)
#define real_cr4_to_pv_guest_cr4(c) \
- ((c) & ~(X86_CR4_PGE | X86_CR4_PSE))
+ ((c) & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_TSD))
void domain_cpuid(struct domain *d,
unsigned int input,
void hvm_hlt(unsigned long rflags);
void hvm_triple_fault(void);
-extern int opt_softtsc;
void hvm_rdtsc_intercept(struct cpu_user_regs *regs);
/* These functions all return X86EMUL return codes. */
uint64_t acpi_pm_tick_to_ns(uint64_t ticks);
uint64_t ns_to_acpi_pm_tick(uint64_t ns);
+extern int opt_softtsc;
+void pv_soft_rdtsc(struct vcpu *v, struct cpu_user_regs *regs);
+
#endif /* __X86_TIME_H__ */